package com.wealth.coupon.util;

import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.joda.time.DateTime;

/**
 * 标签加密
 * @author chan
 */
public class LabelFileEncrypt {
	
//	final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
//			'9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
//			'N', 'P', 'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z' };
	//去掉数字1,0 字母I,O
	final static char[] digits = {  '2', '3', '4', '5', '6', '7', '8',
			'9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
			'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
	
	//生码序列 考虑到 0和 O 1 和 i 打印出来的效果分不清，不参与生码
	public final static String BASE32 = "23456789ABCDEFGHGKLMNPQRSTUVWXYZ";

	//种子
	public final static int SEED = 10*10000;
	
	
	
	/**
	 * 格式化数字
	 * @param number
	 * @param length
	 * @return 长度不足补0，例如number=12， length=3 ，返回012
	 */
	public static String formatNumber(Long number,Integer length){
		if(number.toString().length()>length){
			length = number.toString().length()+1;
		}
		return String.format("%0"+length+"d", number).trim();
	}

	/**
	 * 将十进制的数字转换为指定进制的字符串。
	 * @param i 十进制的数字。
	 * @param system 指定的进制，常见的2/8/16。
	 * @return 转换后的字符串。
	 */
	public static String numericToString(Long num, int system) {
		char[] buf = new char[32];
		int charPos = 32;
		while ((num / system) > 0) {
			buf[--charPos] = digits[(int) (num % system)];
			num /= system;
		}
		buf[--charPos] = digits[(int) (num % system)];
		return new String(buf, charPos, (32 - charPos));
	}

	/**
	 * 将其它进制的数字（字符串形式）转换为十进制的数字。
	 * 
	 * @param s
	 *            其它进制的数字（字符串形式）
	 * @param system
	 *            指定的进制，常见的2/8/16。
	 * @return 转换后的数字。
	 */
	public static long stringToNumeric(String s, int system) {
		char[] buf = new char[s.length()];
		s.getChars(0, s.length(), buf, 0);
		long num = 0;
		for (int i = 0; i < buf.length; i++) {
			for (int j = 0; j < digits.length; j++) {
				if (digits[j] == buf[i]) {
					num += j * Math.pow(system, buf.length - i - 1);
					break;
				}
			}
		}
		return  num;
	}

	
	
	//数字类型的字符串  奇数位相加
	public static int getOddAdd(String str){
		int c1 = 0;
		int temp = str.length();
		//str 长度为奇数
		if (temp % 2 == 1) {
			for (int i = 0; i < temp; i += 2) {
				c1 += Integer.parseInt(str.charAt(i)+"");// 奇数位之和
			}
		}
		//str 长度为偶数
		if (temp % 2 == 0) {
			for (int i = 0; i <= (temp - 1); i += 2) {
				c1 += Integer.parseInt(str.charAt(i)+"");// 奇数位之和
			}
		}
		//System.out.println("奇數位:"+c1);
		return c1;
	}
	
	
	//数字类型的字符串  偶数位相加
	public static int getEvenAdd(String str){
		int c2 = 0;
		int temp = str.length();
		//Str长度为奇数
		if (temp % 2 == 1) {
			
			for (int i = 1; i <temp; i += 2) {
				
				c2 += Integer.parseInt(str.charAt(i)+"");// 偶数位之和
				
			}
		}
		//str 长度为偶数
		if (temp % 2 == 0) {
			
			for (int i = 1; i <= (temp - 1); i += 2) {
				
				c2 += Integer.parseInt(str.charAt(i)+"");// 偶数位之和
				
			}
		}
		
		//System.out.println("偶數位:"+c2);
		return c2;
	}
	
	/**
	 * 返回  数字的 个位数
	 * @return
	 */
	private static int getUnitsDigit(int num){
		return num%10;
	}
	
	/**
	 * 返回  加密的字符串
	 * @return
	 */
	public static String getSuffix(String code){
		return getUnitsDigit(getEvenAdd(code))+""+numericToString(Long.valueOf(code),32)+""+getUnitsDigit(getOddAdd(code));
	}
	
	
	/**
	 * 生成代金券加密算法
	 * create  by chan on 2016-09-21 调整算法
	 */
	public static String encrypt(String uid){
		//序列号
		StringBuffer code =new StringBuffer(uid);

		String millis =String.valueOf(new DateTime().getMillis());
		StringBuffer extcode = new StringBuffer(RandomStringUtils.random(4, LabelFileEncrypt.BASE32));
		extcode.append(millis.substring(millis.length()-4, millis.length()));
		extcode.reverse();
		
		return code.append(extcode).toString();
	}
	
	/**
	 * 加密算法
	 * create  by Tiger 
	 * modify by chan on 2016-09-09 调整算法，引入种子和唯一标识
	 */
	public static String encrypt(String uid,int orginalSN){
		
		//序列号
		String sn = String.valueOf(orginalSN);
		StringBuffer code = new StringBuffer().append(getSuffix(sn));					//序列号压缩 偶数位+进制转换+奇数位
		
		int location = RandomUtils.nextInt(code.length());										//随机数 根据code长度生成随机数
		String key = RandomStringUtils.random(1, LabelFileEncrypt.BASE32);		//随机字符
		code.insert(location, key);																			//随机字符插入随机数的位置
		code.append(location); 																				//末尾插入随机数
		
		code.reverse();																							//倒序

		code.insert(0,uid);																						//唯一标识
		
		System.out.println("-->encrypt:随机数="+location+"，随机字符串="+key+"，  code="+code);
		return code.toString();
	}

	/**
	 * 解密方法
	 * create by chan on 2016-09-11
	 */
	public static String decrypt(String encryptcode){
		try {
			StringBuffer code = new StringBuffer(encryptcode);
			code.delete(0,4);  											//删除唯一标识
			code = code.reverse();									//逆序
			int location = Integer.parseInt(String.valueOf(code.charAt(code.length() - 1)));		//获取随机数位置
			code.deleteCharAt(location);							//删除随机数
			code.deleteCharAt(code.length() - 1);  			//删除随机字符串
		
			int even = code.charAt(0)-48;						//偶数位之和  char和int 在ascii相差48
			int odd= code.charAt(code.length()-1)-48;	//奇数位之和
			long sn = stringToNumeric(code.substring(1,code.length()-1), 32);	//转化为十进制
			String finalSn = String.valueOf(sn);
			int orginalEven = getUnitsDigit(getEvenAdd(finalSn));
			int orginalOdd = getUnitsDigit(getOddAdd(finalSn));
			if(orginalEven==even &&  orginalOdd==odd){		//比较奇偶位是否合法
				System.out.println("-->decrypt:序列号="+String.valueOf(sn)+"\n");
				return finalSn;
			}else{
				System.out.println("-->decrypt:序列号奇偶校验失败");
				return "0";
			}
		} catch (NumberFormatException e) {
			System.out.println("-->decrypt:数字转换过程错误");
			return "0";
		}
	}
	

	/**
	 * 加密解密验证
	 * create by chan on 2016-09-11
	 */
	public static void main(String[] args) {
//		//32进制的4位字符串ZZZZ对应的序列号1,048,575
//		System.out.println(stringToNumeric("ZZZZ", 32)); //1,048,575
//		//设置种子100,000
//		System.out.println(numericToString(10*10000L,32));	//53P2

	/*	String millis =String.valueOf(new DateTime().getMillis());
		String suffix = millis.substring(millis.length()-4, millis.length());
		String code = RandomStringUtils.random(4, LabelFileEncrypt.BASE32)+suffix;
		System.out.println(code);*/
				
//		//唯一标识
//		String uid = RandomStringUtils.random(4, LabelFileEncrypt.BASE32);
//		for (int i = 1; i < 10; i++) {
//			//加密
//			String encryptcode = encrypt(uid, i);
//			//解密
//			decrypt(encryptcode);
//		}
		
		System.out.println(encrypt("UMTV",200006));
		System.out.println(decrypt("UMTV038Z6B6Y"));
	}

}
